// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: fengyang

#pragma once

#include <algorithm>
#include <functional>
#include <map>
#include <string>
#include <vector>

#include "coin2/exchange/base/feed/processor.h"
#include "coin2/exchange/bitget/feed_v1/request_generator.h"
#include "coin2/exchange/bitget_futures/symbology/product.h"

namespace coin2::exchange::bitget_futures::feed_v1 {
namespace impl {

using coin2::exchange::feed::WebsocketConfig;
using coin2::exchange::bitget_futures::symbology::BitgetFuturesProduct;

std::string ConvertToRestSymbol(const std::string& symbol) {
  std::string native_symbol;
  std::vector<std::string> splited = Split(symbol, "_");
  if (splited.size() == 2) {
    // BTCUSD_D2
    auto timestamp = MarketTimestampProvider::GetTimestamp();
    auto product = BitgetFuturesProduct::FromNativeStr(symbol, timestamp);
    const std::string& expiry_str = product.expiry_str();
    std::string date_str = expiry_str.substr(2);
    native_symbol = splited[0] + "_DMCBL_" + date_str;
  } else if (splited.size() == 1) {
    if (StringEndsWith(symbol, "USDT")) {
      native_symbol = symbol + "_UMCBL";
    } else if (StringEndsWith(symbol, "USD")) {
      native_symbol = symbol + "_DMCBL";
    } else if (StringEndsWith(symbol, "PERP")) {
      // USDC
      native_symbol = symbol + "_CMCBL";
    }
  }
  return native_symbol;
}

class BitgetFuturesRequestGenerator : public base::feed::RequestGenerator {
 public:
 explicit BitgetFuturesRequestGenerator(const WebsocketConfig* ws_config)
      : config_(ws_config),
        generator_(ws_config) {}

  std::vector<std::string> GenerateRequests(
      const std::vector<std::string>& channels,
      const std::vector<std::string>& symbols,
      const std::map<std::string, std::string>& channel_templates,
      const std::string& request_template) override {
    std::vector<std::string> reqs;
    std::vector<std::string> ch = channels;
    std::vector<std::string> ch_kline;
    std::vector<std::string> ch_common_rest;
    auto iter = ch.begin();
    while (iter != ch.end()) {
      if (StringStartsWith(*iter, "kline_rest")) {
        ch_kline.push_back(*iter);
        iter = ch.erase(iter);
      } else if (*iter == "index" ||
                 *iter == "funding_rate" ||
                 *iter == "funding_time" ||
                 *iter == "open_interest" ||
                 *iter == "mark_price") {
        ch_common_rest.push_back(*iter);
        iter = ch.erase(iter);
      } else {
        iter++;
      }
    }

    if (!ch_kline.empty()) {
      std::vector<std::string> rest_symbols;
      for (auto& symbol : symbols) {
        rest_symbols.emplace_back(ConvertToRestSymbol(symbol));
      }

      auto requests = generator_.GenerateKlineRequests(ch_kline,
                                                       rest_symbols,
                                                       channel_templates,
                                                       request_template);
      reqs.insert(reqs.end(), requests.begin(), requests.end());
    }

    if (!ch_common_rest.empty()) {
      std::vector<std::string> rest_symbols;
      for (auto& symbol : symbols) {
        rest_symbols.emplace_back(ConvertToRestSymbol(symbol));
      }

      std::vector<std::string> reqs_others = RequestGenerator::GenerateRequests(
        ch_common_rest, rest_symbols, channel_templates, request_template);
      reqs.insert(reqs.end(), reqs_others.begin(), reqs_others.end());
    }

    // websocket channel
    if (!ch.empty()) {
      std::vector<std::string> reqs_others = generator_.GenerateRequests(
        ch, symbols, channel_templates, request_template);
      reqs.insert(reqs.end(), reqs_others.begin(), reqs_others.end());
    }
    return reqs;
  }

  std::vector<std::pair<std::string, std::string>> GenerateHeader(
      const std::vector<std::string>& channels,
      const std::vector<std::string>& symbols,
      const std::map<std::string, std::string>& channel_templates,
      const std::string& request_template) override {
    return generator_.GenerateHeader(channels, symbols, channel_templates, request_template);
  }

 private:
  const WebsocketConfig* config_;
  bitget::feed_v1::BitgetRequestGenerator generator_;
};

}  // namespace impl
using impl::BitgetFuturesRequestGenerator;
}  // namespace coin2::exchange::bitget_futures::feed_v1
